"""
/*
 * Copyright 2011 OpenWAF.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
 """
import os
import sys
from ConfigReader import WAFConfig
import Compiler
import ViewControllerCompiler
import shutil
import UsageAnalyzer
import CssProcessor
from Analyzer import SGlobal, SHelper, SClass
import hashlib
import SharedTypes

def getWebPath(path):
    web_path=os.path.join(path,"web")
    if os.path.exists(web_path):
        return web_path
    web_path=os.path.join(path,"WebContent")
    if os.path.exists(web_path):
        return web_path
    return None
def getSrcPath(path):
    src_path=os.path.join(path,"src","java")
    if os.path.exists(src_path):
        return src_path
    src_path=os.path.join(path,"src")
    if os.path.exists(src_path):
        return src_path
    return None
        
    
def compileApp(path):
    sys.setrecursionlimit(10000)
    if not os.path.exists(path):
        print "ERROR: Path not found for source project :"+path
        sys.exit()
    source_root=path
    source_web_path= getWebPath(source_root)
    source_src_path=getSrcPath(source_root)
    if not(os.path.exists(source_web_path) and os.path.exists(source_src_path)):
        print "ERROR: Not a valid source project directory "+source_root
        sys.exit()
    config_path=os.path.join(source_web_path,"OpenWAFConfig.xml")
    if not os.path.exists(config_path):
        print "ERROR: Config file(OpenWAFConfig.xml) not found in source directory "
        sys.exit()
    WAFConfig.read(config_path)
    target_root=WAFConfig.target_path    
    if not os.path.exists(target_root):
        print "ERROR: Path not found for target project :"+target_root
        sys.exit()
    if source_root==target_root:
        print "Source and target directory are same. "
        sys.exit(0)
    target_web_path= getWebPath(target_root)
    target_src_path=getSrcPath(target_root)
    if not(os.path.exists(target_web_path) and os.path.exists(target_src_path)):
        print "ERROR: Not a valid target project dir"+target_root
        sys.exit()
    client_specific_classes=os.path.join(source_src_path,"client")
    shared_classes=os.path.join(source_src_path,"shared")    
    controllers_path=os.path.join(source_src_path,"controllers")
    if os.path.exists(client_specific_classes): 
        WAFConfig.lib_paths.append(client_specific_classes)
    if os.path.exists(shared_classes): 
        WAFConfig.lib_paths.append(shared_classes)
    model_classes=os.path.join(source_src_path,"server","services")    
    if os.path.exists(model_classes):
        files=os.listdir(model_classes)
        for f in files:
            if f==".svn":continue 
            model_path=os.path.join(model_classes,f)
            Compiler.processJavaFile(model_path,True)         
    ###################
   
    processed_files={}
    cv_pairs={}
    view_codes={}
    processViewControlerPairs(source_web_path, controllers_path, processed_files, cv_pairs)
    """
    files=os.listdir(source_web_path)
    for fname in files:
        if fname==".svn":continue                
        if not fname.endswith(".jsp"):continue
        f_view_path=os.path.join(source_web_path,fname)
        f_controller_path=os.path.join(controllers_path,fname[:-4]+".java")
        if not os.path.exists(f_controller_path):continue
        processed_files[f_view_path]=1
        processed_files[f_controller_path]=1
        cv_pairs[f_view_path]=Compiler.processJavaFile(f_controller_path,False,True)
    """        
    ###################
    Compiler.compileLib()
    import Java2js_SCS
    import Java2js
    proxy_code=Java2js_SCS.SCS.getProxyCode()
    if proxy_code!=None:
        proxy_code=Java2js.getFormatedCode(proxy_code,0)    
    for vfile in cv_pairs:
        cls=cv_pairs[vfile].delcs[0]
        view_codes[vfile]=ViewControllerCompiler.markRefsForVC(vfile, cls)
        UsageAnalyzer.analyze(cls)
    lib_lines1=Compiler.getJSForLib()        
    for vfile in cv_pairs:
        cls=cv_pairs[vfile].delcs[0]
        view_codes[vfile]=ViewControllerCompiler.processControllerViewPair(vfile, cls)
    copyWebContents(source_web_path, target_web_path, view_codes, processed_files)
    copySrcContents(source_src_path, target_src_path)
    copySharedSrcContents(source_src_path, target_src_path)
    copyNecessarySrcFiles(source_src_path, target_src_path)
    #copyContents(source_root,target_root,"",view_codes,processed_files)
    lib_lines2=Compiler.getJSForLib2()
    js_path=os.path.join(target_web_path,WAFConfig.getCompiledJSFileName())
    writeFileIfNecessary(js_path,"\n".join(lib_lines1+lib_lines2))
    
    dir_path=os.path.join(target_src_path,"server","services")
    if os.path.exists(dir_path) and proxy_code!=None:
        writeFileIfNecessary(os.path.join(dir_path,"WAFProxy.java"),proxy_code)
    print " Application Compiled Successfully. "        
    """
    for md5 in SGlobal.hashes:
        if SGlobal.hashes[md5]>1:
            print md5,",",SGlobal.hashes[md5]
    print "Chars saved",SGlobal.chars_saved
    """
def processViewControlerPairs(source_web_path,controllers_path,processed_files,cv_pairs):
    files=os.listdir(source_web_path)
    for fname in files:
        if fname==".svn":continue
        f_view_path=os.path.join(source_web_path,fname)
        if os.path.isdir(f_view_path):
            processViewControlerPairs(f_view_path,os.path.join(controllers_path,fname), processed_files, cv_pairs)                        
        if not ( fname.endswith(".jsp") or fname.endswith(".html")):continue
        f_controller_path=None        
        if fname.endswith(".html"):
            f_controller_path=os.path.join(controllers_path,fname[:-5]+".java")
        elif fname.endswith(".jsp"):
            f_controller_path=os.path.join(controllers_path,fname[:-4]+".java")
        if not os.path.exists(f_controller_path):continue
        processed_files[f_view_path]=1
        processed_files[f_controller_path]=1
        cv_pairs[f_view_path]=Compiler.processJavaFile(f_controller_path,False,True)
def copyNecessarySrcFiles(source,target):
    path=os.path.join(target,"com","openwaf","common","annotation")
    if not os.path.exists(path):
        os.makedirs(path)
    tpath=os.path.join(path,"AsyncRequest.java")    
    cls=SHelper.getClassOnFullName("com.openwaf.common.annotation.AsyncRequest")
    spath=cls.scu.filepath
    copyFileIfNecessary(spath, tpath)
    #import com.openwaf.core.framework.WAFModel;
    path=os.path.join(target,"com","openwaf","core","framework")
    if not os.path.exists(path):
        os.makedirs(path)
    tpath=os.path.join(path,"WAFModel.java")    
    cls=SHelper.getClassOnFullName("com.openwaf.core.framework.WAFModel")
    spath=cls.scu.filepath
    copyFileIfNecessary(spath, tpath)
    #import com.openwaf.core.framework.AsyncCallback;
    path=os.path.join(target,"com","openwaf","core","framework")
    if not os.path.exists(path):
        os.makedirs(path)
    tpath=os.path.join(path,"AsyncCallback.java")    
    cls=SHelper.getClassOnFullName("com.openwaf.core.framework.AsyncCallback")
    spath=cls.scu.filepath
    copyFileIfNecessary(spath, tpath)
    #com.openwaf.server.Utils;
    #com.openwaf.server.JSONSerializable;
    slibpath=None
    for path in WAFConfig.lib_paths:
        slibpath=os.path.join(path,"com","openwaf","server")
        if os.path.exists(slibpath):
            break
        slibpath=None
    if slibpath==None:
        raise Exception("Could not find necessary server classes")
    files=os.listdir(slibpath)
    tpathdir=os.path.join(target,"com","openwaf","server")
    if not os.path.exists(tpathdir):
        os.makedirs(tpathdir)
    for f in files:
        if f==".svn":continue
        spath=os.path.join(slibpath,f)
        tpath=os.path.join(tpathdir,f)
        copyFileIfNecessary(spath, tpath)
    #org.json
    slibpath=None
    for path in WAFConfig.lib_paths:
        slibpath=os.path.join(path,"org","json")
        if os.path.exists(slibpath):
            break
        slibpath=None
    if slibpath==None:
        raise Exception("Could not find json classes in library")
    files=os.listdir(slibpath)
    tpathdir=os.path.join(target,"org","json",)
    if not os.path.exists(tpathdir):
        os.makedirs(tpathdir)
    copySrcContentsSubDir(slibpath,tpathdir)
    
#===
def copySharedSrcContents(source,target):
    files=os.listdir(source)
    for f in files:
        if not(f.lower() in ["shared"]):continue
        spath=os.path.join(source,f)
        tpath=os.path.join(target,f)
        if os.path.isdir(spath):
            if not os.path.exists(tpath):
                os.mkdir(tpath)
            copySharedSrcContentsSubDir(spath,tpath,"shared")
        else:             
            #copyFileIfNecessary(spath, tpath)
            cls=SHelper.getClassOnFullName("shared."+f[:-5])
            if cls==None: raise Exception("Shared Path not found "+f) 
            code=SharedTypes.ST.getCodeSharedTypeJavaFile(cls,spath)
            writeFileIfNecessary(tpath,code)
def copySharedSrcContentsSubDir(source,target,path):
    files=os.listdir(source)
    for f in files:
        if f.lower() in [".svn"]:continue        
        spath=os.path.join(source,f)
        tpath=os.path.join(target,f)
        if os.path.isdir(spath):
            if not os.path.exists(tpath):
                os.mkdir(tpath)
            copySharedSrcContentsSubDir(spath,tpath,path+"."+f)
        else:
            cls=SHelper.getClassOnFullName(path+"."+f[:-5])
            if cls==None: raise Exception("Shared Path not found "+path+"."+f) 
            code=SharedTypes.ST.getCodeSharedTypeJavaFile(cls,spath)
            writeFileIfNecessary(tpath,code)
#==
        
def copySrcContents(source,target):
    files=os.listdir(source)
    for f in files:
        if f.lower() in [".svn","client","controllers","shared"]:continue
        spath=os.path.join(source,f)
        tpath=os.path.join(target,f)
        if os.path.isdir(spath):
            if not os.path.exists(tpath):
                os.mkdir(tpath)
            copySrcContentsSubDir(spath,tpath)
        else:
            copyFileIfNecessary(spath, tpath)
def copySrcContentsSubDir(source,target):
    files=os.listdir(source)
    for f in files:
        if f.lower() in [".svn"]:continue        
        spath=os.path.join(source,f)
        tpath=os.path.join(target,f)
        if os.path.isdir(spath):
            if not os.path.exists(tpath):
                os.mkdir(tpath)
            copySrcContentsSubDir(spath,tpath)
        else:
            copyFileIfNecessary(spath, tpath)

            
def copyWebContents(source,target,view_codes,processed_files):
    files=os.listdir(source)
    for f in files:
        if f.lower() in [".svn","meta-inf","web-inf","openwafconfig.xml"]:continue        
        spath=os.path.join(source,f)
        tpath=os.path.join(target,f)
        if os.path.isdir(spath):
            if not os.path.exists(tpath):
                os.mkdir(tpath)
            copyWebContentsSubDir(spath,tpath,view_codes,processed_files)
        else:
            if view_codes.has_key(spath):
                writeFileIfNecessary(tpath,view_codes[spath])                
            else:
                if spath[-4:]==".css":
                    ls=CssProcessor.processWAFcss(spath,{})
                    if ls!=None:
                        writeFileIfNecessary(tpath, ls)                        
                elif not processed_files.has_key(spath):
                    copyFileIfNecessary(spath, tpath)

def copyWebContentsSubDir(source,target,view_codes,processed_files):
    files=os.listdir(source)
    for f in files:
        if f.lower() in [".svn"]:continue        
        spath=os.path.join(source,f)
        tpath=os.path.join(target,f)
        if os.path.isdir(spath):
            if not os.path.exists(tpath):
                os.mkdir(tpath)
            copyWebContentsSubDir(spath,tpath,view_codes,processed_files)
        else:
            if view_codes.has_key(spath):
                writeFileIfNecessary(tpath,view_codes[spath])                
            else:
                if spath[-4:]==".css":
                    ls=CssProcessor.processWAFcss(spath,{})
                    if ls!=None:
                        writeFileIfNecessary(tpath, ls)                        
                elif not processed_files.has_key(spath):
                    copyFileIfNecessary(spath, tpath)

            
    
def copyFileIfNecessary(s,t):
    modified=False
    if os.path.exists(t) and os.path.getsize(s)!=os.path.getsize(t):
        modified=True
    if (not modified) and os.path.exists(t):
        md5=hashlib.md5()
        md5.update(open(s, "rb").read())
        s_md5=md5.digest()
        md5=hashlib.md5()
        md5.update(open(t, "rb").read())
        t_md5=md5.digest()
        if t_md5==s_md5:            
            return
    shutil.copyfile(s, t)
def writeFileIfNecessary(t,data):
    modified=False
    if os.path.exists(t) and os.path.getsize(t)!=len(data):
        modified=True
    if (not modified) and os.path.exists(t):
        md5=hashlib.md5()
        md5.update(open(t, "rb").read())
        s_md5=md5.digest()
        md5=hashlib.md5()
        md5.update(data)
        t_md5=md5.digest()
        if t_md5==s_md5:            
            return
    f=open(t,"wb")
    f.write(data)
    f.close()
            
        
                
            
        
    
        
if __name__=="__main__":
    a=sys.argv[0]
    [d,s,f]=a.rpartition(os.sep)
    if len(sys.argv)==0:
        print ""
        print "Usage: "+f+" <root_dir_of_source_project>"
        print ""
        sys.exit(0)        
    compileApp(sys.argv[1])
           
    